#include <GL/glew.h>		//Handles extension loading for Windows
#include <string>
#include <fstream>
#include <iostream>
#include <assert.h>

#include "glm/glm.hpp"
#include "Mesh.h"

Mesh::Mesh()
{
	numVertices = 0;
	numPolys = 0;
	hasNormals = false;
	hasTexture = false;
}

Mesh::Mesh(Gfmesh* m)
{
	
	size_t numV = m->vertex_number();			//Number of Vertices
	this->numVertices = numV;
	size_t numI = m->face_number() * 3;				//Number of indices
	this->numPolys = m->face_number();
	
	vertex.reserve(numV * 6);
	const double* d = m->vertex_array();
	const double* n = m->vertex_normal_array();
	glm::vec3 nor;
	for(int i = 0; i < numV; i++)
	{
		vertex.push_back( static_cast<float>(*d) );//vertex
		++d;
		vertex.push_back( static_cast<float>(*d) );//vertex
		++d;
		vertex.push_back( static_cast<float>(*d) );//vertex
		++d;

		nor.x = static_cast<float>(*n);
		++n;
		nor.y = static_cast<float>(*n);
		++n;
		nor.z = static_cast<float>(*n);
		++n;

		nor = glm::normalize(nor);
		vertex.push_back( nor.x );//normal
		vertex.push_back( nor.y );//normal
		vertex.push_back( nor.z );//normal
	
	}

	index.reserve(numI);
	const unsigned int* in = m->face_array();
	for(int i = 0; i < numI; ++i)
	{
		index.push_back( (*in) );
		++in;
	}
	hasNormals = true;
	hasTexture = false;

		//Create GL Buffer
	glGenBuffers(1, &vboID);//Vertices
	glBindBuffer(GL_ARRAY_BUFFER, vboID);
	glBufferData(GL_ARRAY_BUFFER, vertex.size() * sizeof(float), &vertex[0], GL_STATIC_DRAW);//indices size must be in bytes 
	glBindBuffer(GL_ARRAY_BUFFER, 0);

	glGenBuffers(1, &indexID);//Indices
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexID); 
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, index.size() * sizeof(unsigned int), &index[0], GL_STATIC_DRAW);//indices size must be in bytes 
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);//unbind index buffer
	

}

Mesh::~Mesh()
{
	glDeleteBuffers(1, &vboID);
	glDeleteBuffers(1, &indexID);
}


void Mesh::loadPlyFile(const std::string& filename)
{
	std::ifstream fin;	
	std::cout<<"Loading "<<filename<<"...\n";
	fin.open(filename.c_str());
	assert(fin.is_open() && "Could not open Ply file");
	std::string temp = "";
	while(temp != "vertex")
	{
		fin>>temp;
	}

	fin>>numVertices;

	while(temp != "face")
	{
		if(temp == "nx")
		{
			hasNormals = true;
		}
		else if(temp == "s")
		{
			hasTexture = true;
		}
		fin>>temp;
	}

	fin>>numPolys;

	while(temp != "end_header")
	{
		fin>>temp;
	}
	int vertexSize = 3;
	if(hasNormals)
	{
		if(hasTexture)
		{
			vertexSize = 8;
		}
		else
		{
			vertexSize = 6;
		}
	}
	vertex.reserve(numVertices * vertexSize);//x3 for XYZ
	index.reserve(numPolys * 3);//x3 bcos all faces are triangles

	Float data;

	//Read in Vertex data
	for(int i = 0; i < numVertices; ++i)
	{
		for(int j = 0; j < vertexSize; ++j)
		{
			fin>>data;
			vertex.push_back(data);

		}
		//if(!hasNormals)
		//{
		//	//unwanted values
		//	fin>>data;
		//	fin>>data;
		//}
	}

	unsigned int ind;

	for( unsigned int i = 0; i < numPolys; ++i )
	{
		fin>>ind; //first value is number of indices for this face
		for(int j = 0; j < 3; ++j)
		{
			fin>>ind;
			index.push_back(ind);
		}

	}
	std::cout<<"Creating Buffers for "<<filename<<"...\n";
	//Create GL Buffer
	glGenBuffers(1, &vboID);//Vertices
	glBindBuffer(GL_ARRAY_BUFFER, vboID);
	glBufferData(GL_ARRAY_BUFFER, vertex.size() * sizeof(float), &vertex[0], GL_STATIC_DRAW);//indices size must be in bytes 
	glBindBuffer(GL_ARRAY_BUFFER, 0);

	glGenBuffers(1, &indexID);//Indices
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexID); 
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, index.size() * sizeof(unsigned int), &index[0], GL_STATIC_DRAW);//indices size must be in bytes 
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);//unbind index buffer
	


}